#include <iostream>
#include <ctime>
#include <unistd.h>

#include "protocol.hpp"
#include "socket.hpp"

using namespace socket_namespace;

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        std::cerr << "Usage: " << argv[0] << " server-ip server-port" << std::endl;
        exit(1);
    }

    std::string serverip = argv[1];
    uint16_t serverport = std::stoi(argv[2]);

    socketPtr socket = std::make_shared<TCPSocket>();
    // socket->buildClientSocket(serverip, serverport);

    if (!socket->buildClientSocket(serverip, serverport))
    {
        std::cerr << "connect error" << std::endl;
        exit(1);
    }

    srand(time(nullptr) ^ getpid());
    const std::string opers = "+-*/%&^";

    std::string packagestreamqueue;
    while (true)
    {
        // 构建数据
        int x = rand() % 10;
        usleep(x * 50000 + 100);
        int y = rand() % 10;
        usleep(x * y * 50000 + 100);
        char oper = opers[y % opers.size()];

        // 构建请求
        auto req = Factory::buildRequest();
        req->setVal(x, y, oper);

        // 1. 序列化
        std::string reqstr;
        req->Serialize(&reqstr);

        // 2. 添加报头字段
        reqstr = Encode(reqstr);

        std::cout << "###########################" << std::endl;

        std::cout << "request string: \n" << reqstr << std::endl;

        // 3. 发送数据
        socket->Send(reqstr);

        while (true)
        {
            // 4. 读取应答，response
            ssize_t n = socket->Recv(&packagestreamqueue);
            if (n <= 0)
            {
                break;
            }

            // 5. 报文提取，提取报头和有效载荷
            std::string package = Decode(packagestreamqueue);
            if (package.empty())
            {
                continue;
            }

            std::cout << "package: \n" << package << std::endl;

            // 6. 反序列化
            auto resp = Factory::buildResponse();
            resp->Deserialize(package);

            // 7. 打印结果
            resp->PrintforResponse();
            break;
        }
        sleep(1);
    }

    socket->close();

    return 0;
}